﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Drawing;
using System.Reflection;

namespace WinFormUIXMLParser
{
    public class CodeParser
    {
        private const string PanelName = "private System.Windows.Forms.Panel";
        private const string LabelName = "private System.Windows.Forms.Label";
        private const string ButtonName = "private System.Windows.Forms.Button";
        private const string PicBoxName = "private System.Windows.Forms.PictureBox";
        private const string TextBoxName = "private System.Windows.Forms.TextBox";

        private int LinesCount = 0;
        public int ItemsCount
        {
            get
            {
                return dicPositions.Count;
            }
        }

        private string _fileName = "";

        private string _formName = "";

        private List<string> _readingData = new List<string>();

        /// <summary>
        /// 标定所有成员对象的位置
        /// </summary>
        private Dictionary<string, Point> dicPositions = new Dictionary<string, Point>();

        #region static Functions
        private static char[] _separator = new char[]{' ',';'};

        private static char[] _separator1 = new char[] { ' ', ';' };

        private static char[] _separator2 = new char[] {';', '=' };

        private static char[] _separator3 = new char[] {'(', ')', '"', ','};

        private static char[] _separator4 = new char[] {' ', '(', ')', '.'};

        private static string[] _separator5 = new string[] { ";", "+=" };

        private static string[] _separatorColors = new string[] { " ", "(", ")", "byte", "int", ","};

        /// <summary>
        /// 从代码解析得到Size结构的值
        /// </summary>
        /// <param name="source"></param>
        /// <param name="s"></param>
        /// <returns></returns>
        public static bool ParseSize(string sources, out string value)
        {
            value = "";
            if (sources.Contains("System.Drawing.Size"))
            {
                int start = sources.LastIndexOf('(');
                if (start < 0)
                {
                    return false;
                }
                int end = sources.LastIndexOf(')');
                if (end < 0)
                {
                    return false;
                }
                value = sources.Substring(start + 1, end - start - 1);
                value = value.Trim();
                return true;
            }
            return false;
        }

        public static bool ParseLocation(string sources, out string value)
        {
            value = "";
            if (sources.Contains("System.Drawing.Point"))
            {
                int start = sources.LastIndexOf('(');
                if (start < 0)
                {
                    return false;
                }
                int end = sources.LastIndexOf(')');
                if (end < 0)
                {
                    return false;
                }
                value = sources.Substring(start + 1, end - start - 1);
                value = value.Trim();
                return true;
            }
            return false;
        }

        public static bool ParseFontStyle(string source, out string value)
        {
            value = "";
            if (source.Contains("System.Drawing.FontStyle"))
            {
                string[] values = source.Split(new char[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
                value = values.Last().Trim();
                return true;
            }
            return false;
        }

        public static bool ParseFont(string sources, out string value)
        {
            value = "";
            if (sources.Contains("System.Drawing.Font"))
            {
                int start = sources.IndexOf('(');
                if (start < 0)
                {
                    return false;
                }
                int end = sources.LastIndexOf(')');
                if (end < 0)
                {
                    return false;
                }
                string childStr = sources.Substring(start, end - start + 1);
                string[] vaules = childStr.Split(_separator3, StringSplitOptions.RemoveEmptyEntries);
                if (vaules.Length >= 3)
                {
                    string fontName = vaules[0];
                    string fontSize = vaules[1];
                    string fontStyle = "";
                    if (!ParseFontStyle(vaules[2], out fontStyle))
                    {
                        return false;
                    }
                    value = string.Format("{0}, {1}, {2}", fontName, fontSize, fontStyle);
                    return true;
                }
                if (vaules.Length == 2)
                {
                    string fontName = vaules[0];
                    string fontSize = vaules[1];                               
                    value = string.Format("{0}, {1}", fontName, fontSize);
                    return true;
                }
            }
            return false;
        }

        public static bool ParseColor(string sources, out string value)
        {
            value = "";
            if (sources.Contains("System.Drawing.Color"))
            {
                string[] values = sources.Split(new char[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
                value = values.Last().Trim();
                return true;
            }
            if (sources.Contains("System.Drawing.SystemColors"))
            {
                string[] values = sources.Split(new char[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
                value = values.Last().Trim();
                return true;
            }
            if (sources.Contains("System.Drawing.Color.FromArgb"))
            {
                int start = sources.LastIndexOf('(');
                if (start < 0)
                {
                    return false;
                }
                int end = sources.LastIndexOf(')');
                if (end < 0)
                {
                    return false;
                }
                string tStr = sources.Substring(start, end - start + 1);
                string[] values = tStr.Split(_separatorColors, StringSplitOptions.RemoveEmptyEntries);
                if (values.Length == 3)
                {
                    value = string.Format("{0}, {1}, {2}", values[0], values[1], values[2]);
                    return true;
                }
                if (values.Length == 4)
                {
                    value = string.Format("{0}, {1}, {2}, {4}", values[0], values[1], values[2], values[3]);
                    return true;
                }
            }
            return false;
        }

        public static bool ParseText(string sources, out string value)
        {
            value = "";
            string[] values = sources.Split(new char[] {'"', ' '}, StringSplitOptions.RemoveEmptyEntries);
            if (values.Length == 1)
            {
                value = values[0];
                return true;
            }
            return false;
        }

        public static bool ParseTextAlign(string sources, out string value)
        {
            value = "";
            if (sources.Contains("System.Drawing.ContentAlignment"))
            {
                string[] values = sources.Split(new char[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
                value = values.Last().Trim();
                return true;
            }
            return false;
        }

        public static bool ParseTabIndex(string sources, out string value)
        {
            value = sources;
            return true;
        }

        public static bool ParseVisible(string sources, out string value)
        {
            value = sources;
            return true;
        }

        public static bool ParseEnabled(string sources, out string value)
        {
            value = sources;
            return true;
        }

        public static bool ParseTag(string sources, out string value)
        {
            value = sources;
            return true;
        }

        public static bool ParseEventHandler(string sources, out string value)
        {
            value = "";
            if (sources.Contains("System.EventHandler"))
            {
                int start = sources.LastIndexOf('(');
                if (start < 0)
                {
                    return false;
                }
                int end = sources.LastIndexOf(')');
                if (end < 0)
                {
                    return false;
                }
                string tStr = sources.Substring(start, end - start + 1);
                string[] values = tStr.Split(_separator4, StringSplitOptions.RemoveEmptyEntries);
                value = values.Last().Trim();
                return true;
            }
            return false;
        }
        #endregion

        public CodeParser(string file)
        {
            _fileName = file; 
        }

        public void OnHandling()
        {
            OnReading();
            GetPositions();
        }

        private void OnReading()
        {
            _formName = "";
            LinesCount = 0;
            if (!File.Exists(_fileName))
                return;
            StreamReader srReadFile = new StreamReader(_fileName);
            while (!srReadFile.EndOfStream)
            {
                string strReadLine = srReadFile.ReadLine();
                string value = strReadLine.Trim();
                if (!string.IsNullOrEmpty(value))
                {
                    _readingData.Add(value);
                    LinesCount++;
                    if (value.Contains("this.Name"))
                    {
                        string[] words = value.Split(_separator2, StringSplitOptions.RemoveEmptyEntries);
                        string tStr = words.Last().Trim();
                        string tv = "";
                        if (ParseText(tStr, out tv))
                        {
                            _formName = tv;
                        }
                    }
                }                              
            }
            srReadFile.Close();
        }

        private void GetPositions()
        {
            for (int i = 0; i < _readingData.Count - 2; i++)
            {
                string line0 = _readingData[i];
                string line1 = _readingData[i + 1];
                string line2 = _readingData[i + 2];
                if (line0.Equals(@"//") && line2.Equals(@"//"))
                {
                    string[] words = line1.Split(new char[] {' '}, StringSplitOptions.RemoveEmptyEntries);
                    if (words[0].Equals(@"//") && words.Length == 2)
                    {
                        string field = words.Last().Trim();
                        int start = i + 3;
                        int end = _readingData.FindIndex(start, r => r.Equals(@"//"));
                        if (end == -1)
                        {
                            end = _readingData.FindIndex(start, r => r.Equals(@"}"));
                        }
                        if (end > 0)
                        {
                            dicPositions.Add(field, new Point(start, end-1));
                            i = end - 1;
                        }                      
                    }               
                }
            }
        }

        private bool TryParseToString(string key, string source, out string value)
        {
            value = "";
            switch (key)
            {
                case "Location":
                    return ParseLocation(source, out value);
                case "Size":
                    return ParseSize(source, out value);
                case "Name":
                    return ParseText(source, out value);
                case "Enabled":
                    return ParseEnabled(source, out value);
                case "Visible":
                    return ParseVisible(source, out value);              
                case "Text":
                    return ParseText(source, out value);
                case "Tag":
                    return ParseTag(source, out value);
                case "TabIndex":
                    return ParseTabIndex(source, out value);
                case "ForeColor":
                    return ParseColor(source, out value);
                case "BackColor":
                    return ParseColor(source, out value);
                case "Click":
                    return ParseEventHandler(source, out value);
                case "Enter":
                    return ParseEventHandler(source, out value);
                case "Font":
                    return ParseFont(source, out value);
                case "TextAlign":
                    return ParseTextAlign(source, out value);
                default:
                    break;
            }
            return false;
        }

        private string GetDefinitionClassString(string source)
        {          
            source = source.Trim();
            string value = source;
            if (source.StartsWith("new "))
            {
                value = source.Substring(4, source.Length - 4);
            }
            return value;
        }

        public T ParseXMLObject<T>(string name) where T : new()
        {
            T temp = new T();
            Point pos = dicPositions[name];
            int count = pos.Y - pos.X + 1;
            List<string> lines = _readingData.Skip(pos.X).Take(count).ToList();
            Type type = typeof(T);
            for (int i = 0; i < lines.Count; i++)
            {
                if (string.IsNullOrEmpty(lines[i]))
                {
                    continue;
                }
                if (!lines[i].Contains("="))
                {
                    continue;
                }

                string[] words = null;
                if (lines[i].Contains("+="))
                {
                    words = lines[i].Split(_separator5, StringSplitOptions.RemoveEmptyEntries);
                }
                else
                {
                    words = lines[i].Split(_separator2, StringSplitOptions.RemoveEmptyEntries);
                }
                if (words == null || words.Length < 2)
                {
                    continue;
                }
                string parsingString = GetDefinitionClassString(words[1]);               
                string[] objs = words[0].Split(new char[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
                string key = objs.Last().Trim();
                string value = "";
                if (TryParseToString(key, parsingString, out value))
                {
                    PropertyInfo propertyInfo = type.GetProperty(key);
                    if (propertyInfo == null)
                    {
                        continue;
                    }
                    if (propertyInfo.PropertyType == typeof(bool))
                    {
                        propertyInfo.SetValue(temp, StaticTypes.ConvertToBoolean(value, true), null);
                    }
                    else
                    {
                        propertyInfo.SetValue(temp, value, null);
                    }
                }
                else
                {
                    // add other code
                }
            }
            return temp;
        }

        public List<XmlTextBoxObject> ParseTextBoxs()
        {
            List<XmlTextBoxObject> list = new List<XmlTextBoxObject>();        
           
            // 首先找出所有声明的对象
            for (int i = 0; i < _readingData.Count; i++)
            {
                string lineText = _readingData[i];
                if (lineText.Contains(TextBoxName))
                {
                    string[] words = lineText.Split(_separator, StringSplitOptions.RemoveEmptyEntries);
                    string lastWord = words.Last().Trim();
                    XmlTextBoxObject obj = new XmlTextBoxObject();
                    obj.Name = lastWord;
                    list.Add(obj);
                }
            }

            // 然后逐一对TextBox对象进行解析
            for (int i = 0; i < list.Count; i++)
            {
                list[i] = ParseXMLObject<XmlTextBoxObject>(list[i].Name);
                if (string.IsNullOrEmpty(list[i].Tag))
                {
                    if (list[i].Name.StartsWith("textBox"))
                    {
                        list[i].Tag = list[i].Name.Substring(7, list[i].Name.Length - 7);
                    }
                }
            }
            return list;
        }

        public List<XmlLabelObject> ParseLabels()
        {
            List<XmlLabelObject> list = new List<XmlLabelObject>();
            // 首先找出所有声明的对象
            for (int i = 0; i < _readingData.Count; i++)
            {
                string lineText = _readingData[i];
                if (lineText.Contains(LabelName))
                {
                    string[] words = lineText.Split(_separator, StringSplitOptions.RemoveEmptyEntries);
                    string lastWord = words.Last();
                    XmlLabelObject obj = new XmlLabelObject();
                    obj.Name = lastWord;
                    list.Add(obj);
                }
            }

            // 然后逐一对Label对象进行解析
            for (int i = 0; i < list.Count; i++)
            {
                list[i] = ParseXMLObject<XmlLabelObject>(list[i].Name);
            }
            return list;
        }

        public List<XmlButtonObject> ParseButtons()
        {
            List<XmlButtonObject> list = new List<XmlButtonObject>();
            // 首先找出所有声明的对象
            for (int i = 0; i < _readingData.Count; i++)
            {
                string lineText = _readingData[i];
                if (lineText.Contains(ButtonName))
                {
                    string[] words = lineText.Split(_separator, StringSplitOptions.RemoveEmptyEntries);
                    string lastWord = words.Last();
                    XmlButtonObject obj = new XmlButtonObject();
                    obj.Name = lastWord;
                    list.Add(obj);
                }
            }

            // 然后逐一对Button对象进行解析
            for (int i = 0; i < list.Count; i++)
            {
                list[i] = ParseXMLObject<XmlButtonObject>(list[i].Name);
            }
            return list;
        }

        public XmlFormObject ParseForms()
        {
            if (string.IsNullOrEmpty(_formName))
            {
                return null;
            }
            XmlFormObject form = new XmlFormObject();
            form = ParseXMLObject<XmlFormObject>(_formName);
            return form;
        }

        public List<XmlPictureBoxObject> ParsePictureBoxs()
        {
            List<XmlPictureBoxObject> list = new List<XmlPictureBoxObject>();
            // 首先找出所有声明的对象
            for (int i = 0; i < _readingData.Count; i++)
            {
                string lineText = _readingData[i];
                if (lineText.Contains(PicBoxName))
                {
                    string[] words = lineText.Split(_separator, StringSplitOptions.RemoveEmptyEntries);
                    string lastWord = words.Last();
                    XmlPictureBoxObject obj = new XmlPictureBoxObject();
                    obj.Name = lastWord;
                    list.Add(obj);
                }
            }

            // 然后逐一对PictureBox对象进行解析
            for (int i = 0; i < list.Count; i++)
            {
                list[i] = ParseXMLObject<XmlPictureBoxObject>(list[i].Name);
            }
            return list;
        }

        public List<XmlPanelObject> ParsePanels()
        {
            List<XmlPanelObject> list = new List<XmlPanelObject>();
            // 首先找出所有声明的对象
            for (int i = 0; i < _readingData.Count; i++)
            {
                string lineText = _readingData[i];
                if (lineText.Contains(PicBoxName))
                {
                    string[] words = lineText.Split(_separator, StringSplitOptions.RemoveEmptyEntries);
                    string lastWord = words.Last();
                    XmlPanelObject obj = new XmlPanelObject();
                    obj.Name = lastWord;
                    list.Add(obj);
                }
            }

            // 然后逐一对Panel对象进行解析
            for (int i = 0; i < list.Count; i++)
            {
                list[i] = ParseXMLObject<XmlPanelObject>(list[i].Name);
            }
            return list;
        }
    }
}
